相信各位 JavaScript 開發者,對表達式(Expression)與陳述式(statement)的概念不陌生,這兩個概念可以說是初階前端工程師必考的面試題,但這個概念為什麼重要到每間公司都要考你呢?也許看完以下的說明,就會知道表達式與陳述式的概念為什麼在 FP 很重要了。
《Speaking JavaScript》 的作者 Dr. Axel Rauschmayer 曾在其部落格發表過一篇文章《Expressions versus statements in JavaScript》,在此文章中針對 JavaScript 表達式與陳述式的種類進行了詳盡的介紹,Dr. Axel Rauschmayer 針對這兩者的差異說道:「表達式會產生值,陳述式執行某些行為。」
聽起來是不是有點不直覺?不好理解呢?
老實說,在一開始自己擠也花了許久的時間來理解表達式與陳述式的概念,或許我們可以透過下方範例更了解什麼叫作「會產出值(回傳值)」的概念:
const a = 1;
console.log(a);
// 1
我們宣告一個變數,再次要取用變數時,會發現 a
變數會給我們一個預先存進去的值 1
。
此外,經驗告訴我們,變數的右側可不只能放純值、物件陣列,還可以進行運算:
const b = 1 + 1;
console.log(b);
// 2
由此可見,變數可以產出某種值,所以是一個經典表達式的例子。
換個方式思考,可以被存成變數的東西,一定要可以回傳某個值,才能被變數存起來,試想如果「值」本人如果不告訴變數自己帶有什麼樣的值,變數大概也無從判斷你想把什麼放進自己裡面吧?
因此,要可以被放進變數裡的東西,一定要是表達式!
所以除了基本型別、物件、陣列外,運算式也是一種表達式,包括短路計算(註一)、三元運算式本身也是一種會回傳值的 Expression 。
在前一個章節,我們聊到函式是「一等公民」,除了可以用來解決重複性的邏輯外我們更可以把函式看作一種「值」,所以函式也是一種表達式,在我們沒有主動回傳某個值時,JavaScript 就會自動幫我們的函式回傳 undefined
。
在後續的章節中,我們會看到更多、各式各樣的表達式。
當了解什麼是表達式後,了解什麼是陳述式就沒有那麼難了,如果我們用「會執行某個行為」來定義 陳述式,感覺有點不明確,難道你不覺得「回傳」也很像要執行某個動作嗎?
於是在觀察了眾多開發者的說法後,自己覺得直接把**陳述式定義成「不能直接賦予進變數中,或是做為參數使用」**似乎更好理解。
舉例來說:
以上這些 JavaScript 的語法,都沒有辦法被當成一個「獨立的值」賦予進變數內,或是做為參數使用,甚至我們常使用的 forEach
根本不能使用 return
關鍵字。
當然說到這邊你可能會發現:if…else…
或是 switch
也可以傳回傳某個值呀?
沒錯!Dr. Axel Rauschmayer 在文中提及:
「Wherever JavaScript expects a statement, you can also write an expression. Such a statement is called an expression statement. The reverse does not hold: you cannot write a statement where JavaScript expects an expression. For example, an if statement cannot become the argument of a function.」
在 JavaScript 中預期使用陳述式的地方,我們同樣也可以使用表達式取代,這樣的陳述我們稱其為「表達陳述式」,但要注意的是,表達陳述式除非有用函式額外包裝起來,不然同樣沒有辦法作為參數或是變數的值。
但如果反過來呢?是不是有「陳述表達式」這種概念?如果我們還記得關於表達式的定義是:「要產出值」,就會發現這樣的概念是不成立的,因為不能獨立作為變數值的程式碼,就不能算上表達式!
為什麼我們需要在討論 FP 的途中,特別花一個篇幅來討論表達式與陳述式的差異呢?
誠如先前所提到的, FP 可以解決「JavaScript 」語言特性中不嚴謹的一些問題,特別是針對一些難以預期的值的改變、覆寫的情境。
透過上方的範例,我們理解到:表達式會回傳值,陳述式則是負責進行流程判斷;表達式可以獨立被賦予到變數中,或是參數做使用,但陳述式不行。
還記得我們先前所提到為什麼我們要在 JavaScript 中導入 FP 嗎?那是因為我們想要盡量避免不必要的錯誤。
而在 FP 是用什麼手段,讓 JavaScript 是弱型別的狀況下,依然保有可預期的結果?這裡我們先透露個小提示,在 FP 我們都是使用表達式來解決問題,至於為什麼?透過什麼樣的手段?為什麼我不在 FP 中使用陳述式?
以上的問題,我們會在後續的章節所提到,下一個章節,讓我們來小小複習一下目前為止所學習到的內容。
console.log(true && 3+1);
// 4
console.log(3+1 && true)
// true
使用 && 運算子進行值的運算,當兩者皆為真值(Truthy Value)時,會回傳後者的回傳值,若有其中之一不是真值,則回傳 false
。
console.log(false || 3+1);
// 4
console.log(3+1 || undefined)
// 4
使用 || 運算子進行值的運算,會回傳優先讀取到的「真值」之回傳值,若沒有任何真值,則回傳 false
。